package com.mkx.multitier.resource;

import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 通用资源池实现，管理资源的创建、获取和释放
 */
public class GenericResourcePool<T> implements ResourcePool<T> {
    private final String poolName;
    private final ResourceFactory<T> resourceFactory;
    private final int initialSize;
    private final int maxSize;
    private final BlockingQueue<T> availableResources;
    private final Set<T> allocatedResources;
    private final AtomicInteger createdCount = new AtomicInteger(0);
    private volatile boolean isRunning = false;
    
    /**
     * 资源工厂接口，用于创建资源实例
     */
    public interface ResourceFactory<T> {
        T createResource();
        void destroyResource(T resource);
        boolean validateResource(T resource);
    }
    
    /**
     * 构造函数
     */
    public GenericResourcePool(String poolName, ResourceFactory<T> resourceFactory, int initialSize, int maxSize) {
        if (initialSize < 0 || maxSize < initialSize) {
            throw new IllegalArgumentException("Invalid pool size parameters");
        }
        
        this.poolName = poolName;
        this.resourceFactory = resourceFactory;
        this.initialSize = initialSize;
        this.maxSize = maxSize;
        this.availableResources = new LinkedBlockingQueue<>(maxSize);
        this.allocatedResources = new HashSet<>(maxSize);
    }
    
    @Override
    public synchronized void initialize() {
        if (isRunning) {
            return;
        }
        
        System.out.println("Initializing resource pool: " + poolName);
        
        // 预创建初始数量的资源
        for (int i = 0; i < initialSize; i++) {
            T resource = createResource();
            if (resource != null) {
                availableResources.offer(resource);
            }
        }
        
        isRunning = true;
        System.out.println("Resource pool initialized: " + poolName + ", created " + createdCount.get() + " resources");
    }
    
    @Override
    public T acquire() throws InterruptedException {
        if (!isRunning) {
            throw new IllegalStateException("Resource pool is not initialized");
        }
        
        T resource = null;
        
        // 尝试从可用资源队列获取
        resource = availableResources.poll();
        
        // 如果没有可用资源且未达到最大容量，则创建新资源
        if (resource == null && createdCount.get() < maxSize) {
            synchronized (this) {
                // 双重检查，避免多线程重复创建
                if (createdCount.get() < maxSize) {
                    resource = createResource();
                }
            }
        }
        
        // 如果还是没有资源，则等待资源可用
        if (resource == null) {
            resource = availableResources.poll();
        }
        
        if (resource != null) {
            // 验证资源是否有效
            if (!validate(resource)) {
                synchronized (this) {
                    createdCount.decrementAndGet();
                    destroyResource(resource);
                    // 递归尝试获取新资源
                    return acquire();
                }
            }
            
            // 添加到已分配集合
            synchronized (allocatedResources) {
                allocatedResources.add(resource);
            }
        }
        
        return resource;
    }
    
    @Override
    public T acquire(long timeout, TimeUnit unit) throws InterruptedException {
        if (!isRunning) {
            throw new IllegalStateException("Resource pool is not initialized");
        }
        
        // 尝试在超时时间内获取资源
        long remainingNanos = unit.toNanos(timeout);
        long deadline = System.nanoTime() + remainingNanos;
        
        T resource = null;
        
        // 先尝试从可用队列获取
        resource = availableResources.poll(remainingNanos, TimeUnit.NANOSECONDS);
        remainingNanos = deadline - System.nanoTime();
        
        // 如果没有获取到且时间还有剩余，尝试创建新资源
        if (resource == null && remainingNanos > 0 && createdCount.get() < maxSize) {
            synchronized (this) {
                if (createdCount.get() < maxSize) {
                    resource = createResource();
                }
            }
        }
        
        // 如果还是没有资源且时间还有剩余，再等待一次
        if (resource == null && remainingNanos > 0) {
            resource = availableResources.poll(remainingNanos, TimeUnit.NANOSECONDS);
        }
        
        if (resource != null) {
            // 验证资源
            if (!validate(resource)) {
                synchronized (this) {
                    createdCount.decrementAndGet();
                    destroyResource(resource);
                    // 尝试获取有效资源，但不等待
                    return availableResources.poll();
                }
            }
            
            synchronized (allocatedResources) {
                allocatedResources.add(resource);
            }
        }
        
        return resource;
    }
    
    @Override
    public boolean release(T resource) {
        if (!isRunning || resource == null) {
            return false;
        }
        
        synchronized (allocatedResources) {
            if (!allocatedResources.remove(resource)) {
                return false; // 资源不是从这个池分配的
            }
        }
        
        // 验证资源是否仍然有效
        if (!validate(resource)) {
            synchronized (this) {
                createdCount.decrementAndGet();
                destroyResource(resource);
            }
            return false;
        }
        
        // 归还到可用队列
        return availableResources.offer(resource);
    }
    
    @Override
    public synchronized void shutdown() {
        if (!isRunning) {
            return;
        }
        
        System.out.println("Shutting down resource pool: " + poolName);
        
        isRunning = false;
        
        // 销毁所有可用资源
        T resource;
        while ((resource = availableResources.poll()) != null) {
            destroyResource(resource);
        }
        
        // 销毁所有已分配资源（强制关闭）
        synchronized (allocatedResources) {
            for (T allocatedResource : allocatedResources) {
                destroyResource(allocatedResource);
            }
            allocatedResources.clear();
        }
        
        createdCount.set(0);
        System.out.println("Resource pool shut down: " + poolName);
    }
    
    @Override
    public int size() {
        return createdCount.get();
    }
    
    @Override
    public int availableCount() {
        return availableResources.size();
    }
    
    @Override
    public int allocatedCount() {
        synchronized (allocatedResources) {
            return allocatedResources.size();
        }
    }
    
    @Override
    public synchronized void resize(int newSize) {
        if (newSize < 0) {
            throw new IllegalArgumentException("New size cannot be negative");
        }
        
        // 如果新大小大于当前大小，创建更多资源
        while (createdCount.get() < newSize && createdCount.get() < maxSize) {
            T resource = createResource();
            if (resource != null) {
                availableResources.offer(resource);
            }
        }
        
        // 如果新大小小于当前大小，移除多余资源
        while (createdCount.get() > newSize) {
            T resource = availableResources.poll();
            if (resource != null) {
                createdCount.decrementAndGet();
                destroyResource(resource);
            } else {
                break; // 没有可用资源可移除
            }
        }
        
        System.out.println("Resource pool resized: " + poolName + ", new size: " + createdCount.get());
    }
    
    @Override
    public boolean validate(T resource) {
        return resourceFactory.validateResource(resource);
    }
    
    @Override
    public String getPoolName() {
        return poolName;
    }
    
    /**
     * 创建新资源
     */
    private T createResource() {
        try {
            T resource = resourceFactory.createResource();
            if (resource != null) {
                createdCount.incrementAndGet();
            }
            return resource;
        } catch (Exception e) {
            System.err.println("Failed to create resource in pool " + poolName + ": " + e.getMessage());
            return null;
        }
    }
    
    /**
     * 销毁资源
     */
    private void destroyResource(T resource) {
        try {
            resourceFactory.destroyResource(resource);
        } catch (Exception e) {
            System.err.println("Error destroying resource in pool " + poolName + ": " + e.getMessage());
        }
    }
    
    @Override
    public String toString() {
        return "GenericResourcePool{" +
                "name='" + poolName + "'" +
                ", total=" + createdCount.get() +
                ", available=" + availableResources.size() +
                ", allocated=" + allocatedCount() +
                ", maxSize=" + maxSize +
                "}";
    }
}
